package cn.tedu.charging.order.service;

import cn.tedu.charging.common.pojo.message.ChargingCheckResultMessage;
import cn.tedu.charging.common.pojo.message.DelayCheckMessage;
import cn.tedu.charging.common.pojo.po.ChargingBillFailPO;
import cn.tedu.charging.common.pojo.po.ChargingBillSuccessPO;
import cn.tedu.charging.common.protocol.WebSocketMessage;
import cn.tedu.charging.order.mapper.BillFailMapper;
import cn.tedu.charging.order.mapper.BillSuccessMapper;
import cn.tedu.charging.order.mqtt.MqttContext;
import cn.tedu.charging.order.websocket.WebSocketServer;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * 专属于mqtt消费者 处理消费逻辑的业务层
 */
@Component
@Slf4j
public class ConsumerService {
    //第一个业务逻辑,就是处理 设备反馈消息
    @Autowired
    private BillSuccessMapper billSuccessMapper;
    @Autowired
    private BillFailMapper billFailMapper;

    //@Autowired 不自动注入  mqttContext null
    private MqttContext mqttContext;

    public void setMqttContext(MqttContext mqttContext) {
        this.mqttContext = mqttContext;
    }

    public void handleCheckNoRes(DelayCheckMessage msg){
        log.info("延迟消息消费,开始执行");
        //1.check检查是否存在订单
        boolean exists=checkBillExists(msg.getOrderNo());
        if (exists){
            log.info("订单1分钟之内有反馈结果,orderNo:{}",msg.getOrderNo());
            return;
        }
        //2.没有反馈结果,没有success也没有fail 按照fail处理
        //2.1新增延迟无反馈的fail
        ChargingBillFailPO po=new ChargingBillFailPO();
        po.setBillId(msg.getOrderNo());
        po.setUserId(msg.getUserId());
        po.setCreateTime(new Date());
        po.setUpdateTime(new Date());
        po.setFailDesc("设备无响应失败");
        billFailMapper.insert(po);
        //2.2 UNDO 调用设备无响应 默认设备有毛病 告诉设备服务 充电桩 有问题
        //2.3 告诉通知用户 发送实时消息换枪 换桩
        //2.5 websocket推送消息给用户 通知换枪
        //创建 统一格式的消息体 WebSocketMessage
        WebSocketMessage webSocketMessage = new WebSocketMessage();
        //设置消息的类型
        // 1 订单问题 2 用户余额不足 3 充电进度 推荐写到常量或者枚举类中
        webSocketMessage.setState(1); //魔数 推荐写到常量或者枚举类中
        //设置消息的数据
        //设置消息
        webSocketMessage.setMessage("设备无响应");
        //webSocketMessage.setData(msg);
        webSocketMessage.setData("B下单失败,设备无响应,请换枪,非常抱歉,赠送一张优惠券");
        //通过mqttContext 获取websocketServer
        WebSocketServer webSocketServer = mqttContext.getWebSocketServer();
        // 调用 websocketServer的 sendMsg2User 方法给用户 msg.getUserId() 发送 webSocketMessage
        webSocketServer.sendMsg2User(msg.getUserId(),webSocketMessage);

    }

    public void handlerCheckResult(ChargingCheckResultMessage msg){
        log.info("设备自检反馈消费,开始执行");
        //1.判断是否存在成功或失败单
        boolean exists=checkBillExists(msg.getOrderNo());
        if (exists){
            log.info("订单已经存在,无需消费,orderNo:{}",msg.getOrderNo());
            return;
        }
        //2.判断 反馈自检结果是成功还是失败
        if (msg.getResult()){
            //2.1 新增一个success订单
            saveSuccessBill(msg);
            //2.2 UNDO新增成功订单.启动充电完成了,下一步 发送命令让设备 开始充电
        }else{
            //2.3失败订单 启动充电失败
            saveFailBill(msg);
            //2.4 undo 远程调用设备服务 根据失败原因判断是否要让设备修改枪状态
            //2.5 websocket推送消息给用户 通知换枪
            //创建 统一格式的消息体 WebSocketMessage
            WebSocketMessage webSocketMessage = new WebSocketMessage();
            //设置消息的类型
            // 1 订单问题 2 用户余额不足 3 充电进度 推荐写到常量或者枚举类中
            webSocketMessage.setState(1); //魔数 推荐写到常量或者枚举类中
            //设置消息的数据
            webSocketMessage.setData(msg);
            //通过mqttContext 获取websocketServer
            WebSocketServer webSocketServer = mqttContext.getWebSocketServer();
            // 调用 websocketServer的 sendMsg2User 方法给用户 msg.getUserId() 发送 webSocketMessage
            webSocketServer.sendMsg2User(msg.getUserId(),webSocketMessage);

        }
    }

    private void saveFailBill(ChargingCheckResultMessage msg) {
        ChargingBillFailPO po=new ChargingBillFailPO();
        //billId
        po.setBillId(msg.getOrderNo());
        //userId
        po.setUserId(msg.getUserId());
        //create update
        po.setCreateTime(new Date());
        po.setUpdateTime(po.getCreateTime());
        //fail_desc 失败描述 设备自检错误
        po.setFailDesc("设备自检错误");
        billFailMapper.insert(po);
    }

    private void saveSuccessBill(ChargingCheckResultMessage msg) {
        //insert into charging_bill_success (字段)
        ChargingBillSuccessPO po=new ChargingBillSuccessPO();
        //billId
        po.setBillId(msg.getOrderNo());
        //userId
        po.setUserId(msg.getUserId());
        //时间 create update
        po.setCreateTime(new Date());
        po.setUpdateTime(po.getCreateTime());
        //[重要] status 成功订单状态 后续判断订单是否正常合法结束 status=0 开始且正在充电
        po.setBillStatus(1);
        billSuccessMapper.insert(po);
    }

    private boolean checkBillExists(String orderNo) {
        //1.准备2个私有方法 单独查询success和fail
        //通过 业务 流程 手段保证只能一个orderNo 只存在一个success或fail
        return checkSuccessExists(orderNo)||checkFailExists(orderNo);
    }
    private boolean checkFailExists(String orderNo) {
        //select count from fail where bill_id=#{orderNo}
        QueryWrapper queryWrapper=new QueryWrapper();
        queryWrapper.eq("bill_id",orderNo);
        return billFailMapper.selectCount(queryWrapper)>0;
    }
    private boolean checkSuccessExists(String orderNo) {
        //select count from success where bill_id=#{orderNo}
        QueryWrapper queryWrapper=new QueryWrapper();
        queryWrapper.eq("bill_id",orderNo);
        return billSuccessMapper.selectCount(queryWrapper)>0;
    }

}
